Chapter 6
Maps
This Chapter does not have Exercises. The code and examples below show map plotting in R with tidyverse and sf with examples from India.
6.2 Simple features maps
First, we download a shape file of India’s map (from here) and plot a map of India with latest state and Union Territory boundaries. The code below shows a simple example of ease of plotting with ggplot() and geom_sf() along with labeling official names of States and Union Territories.
Code
# Reading in the shape file
india_map <- read_sf(here::here("data",
"india_map",
"India_State_Boundary.shp")) |>
# tidy names of variables
rename(state = State_Name) |>
# Renaming to official names. Official names taken from Government:
# https://knowindia.india.gov.in/states-uts/
mutate(state = case_when(
state == "Andaman & Nicobar" ~ "Andaman and Nicobar Islands",
state == "Daman and Diu and Dadra and Nagar Haveli" ~ "Dadra and Nagar Haveli and Daman & Diu",
state == "Jammu and Kashmir" ~ "Jammu & Kashmir",
state == "Telengana" ~ "Telangana",
.default = state
))
# Add names of Union Territories
union_territories <- c(
"Andaman and Nicobar Islands",
"Chandigarh",
"Dadra and Nagar Haveli and Daman & Diu",
"Delhi",
"Jammu & Kashmir",
"Ladakh",
"Lakshadweep",
"Puducherry"
)
india_map |>
mutate(type = if_else(state %in% union_territories,
"Union Territory",
"State")) |>
ggplot(aes(geometry = geometry,
col = type)) +
geom_sf(col = "darkgrey", fill = "white") +
geom_sf_text(aes(label = state,
size = type)) +
scale_color_manual(values = c("darkblue", "darkred")) +
scale_size_discrete(range = c(3.5, 2.5)) +
theme_map() +
theme(legend.position = "bottom") +
labs(col = NULL) +
annotation_scale(bar_cols = c("darkgrey", "white"),
location = "br") +
annotation_north_arrow(location = "tr",
which_north = "true") +
guides(size = "none")
6.4 Working with sf data
Plotting a specific state from i..e, Haryana, and its districts along with their area (in thousand sq. km.) using official data from Survey of India, and adding geoms from other metadata - area and length of district borders: –
Code
haryana_map <- read_sf(here::here("data",
"haryana_map",
"HARYANA_DISTRICT_BDY.shp")) |>
janitor::clean_names() |>
mutate(
district = str_replace_all(district,
pattern = ">",
replacement = "A"),
state = str_replace_all(state,
pattern = ">",
replacement = "A"),
district = case_when(
district == "FAR|DABAD" ~ "FARIDABAD",
district == "J|ND" ~ "JIND",
district == "PAN|PAT" ~ "PANIPAT",
district == "SON|PAT" ~ "SONIPAT",
.default = district
),
district = snakecase::to_title_case(district)
)
haryana_map |>
select(-c(remarks, state_lgd, district_l)) |>
arrange(desc(shape_area)) |>
mutate(
rank = row_number(),
area = round(shape_area/1e9, 2),
font_col = district %in% c("Hisar", "Sirsa")
) |>
ggplot(aes(geometry = geometry,
label = paste0(district),
fill = shape_area/1e6)) +
geom_sf(col = "white") +
geom_sf_text(aes(col = font_col),
size = 4) +
theme_map() +
annotation_scale(location = "br") +
annotation_north_arrow(location = "tr") +
labs(fill = "District Area\n(in sq. km.)",
title = "Haryana: Districts (with area)") +
scale_fill_viridis_c(labels = scales::label_comma(),
option = "G") +
scale_color_manual(values = c("white", "black")) +
guides(col = "none")
Chloropleth with tmap
A package to create chloropleths very easily is the tmap package (Tennekes 2018) of R . However, is uses a very different syntax than ggplot2 .
Code
library(tmap)
tm_hy <- haryana_map |>
mutate(area = shape_area/1e6)
t_hy <- tm_shape(tm_hy) +
tm_polygons(col = "area",
title = "District Area\n(in sq. km.)",
border.col = "black",
interactive = TRUE,
style = "pretty")
t_hy
An interesting feature is the ability to plot interactive maps: –
Adding leaflet maps to Chloropleths
Code
library(leaflet)
# Create a quantile of colours' palette to be used
pal_hy <- colorQuantile("Blues",
domain = NULL,
n = 5)
# Create vector of text to display on pop-ups in leaflet map
p_popup <- paste0(haryana_map$district,
" District. Area: ",
round(haryana_map$shape_area/1e6, 0),
" sq. km.")
# Create leaflet map
# Data set
haryana_map |>
# Transform polygons into CRS=4326 since leaflet only understand that
st_transform(crs = 4326) |>
# Begin leaflet map
leaflet() |>
# Add polygons from the geometry column of the data-set
addPolygons(
stroke = FALSE, # remove polygon borders
fillColor = ~ pal_hy(shape_area/1e6), # set fill color with function
fillOpacity = 0.6, # translucent to see background map
smoothFactor = 0.5, # make it nicer
popup = p_popup, # add popup
group = "District Area" # a Group label for leaflet options
) |>
# Add base map from leaflet; default is Open Street Maps
addTiles() |> # Adding Base Map
# Adding a legend
addLegend(
position = "bottomright", # location
pal = pal_hy, # palette function
values = ~shape_area/1e6, # value to be passed to palette function
title = "District Area (sq. km.)" # legend title
) |>
# Adding an option to view different base maps
addLayersControl(
baseGroups = c("OSM", "Carto"),
overlayGroups = c("District Area")
)